//
//  main.m
//  RunTime的一些深入
//
//  Created by ZhouFahong on 16/7/22.
//  Copyright © 2016年 ZhouFahong. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AppDelegate.h"


#import "objc/runtime.h"
#import "MyClass.h"


void imp_submethod1(id self,SEL _cmd){
    
    NSLog(@"%s",__func__);
    
}

int main(int argc, char * argv[]) {
    
    @autoreleasepool {
        
        
        MyClass *myClass = [[MyClass alloc] init];
        
        unsigned int outCount = 0;
        
        
        
        Class cls = myClass.class;
        
        
        
        // 类名
        
        NSLog(@"class name: %s", class_getName(cls));
        
        
        
        NSLog(@"==========================================================");
        
        
        
        // 父类
        
        NSLog(@"super class name: %s", class_getName(class_getSuperclass(cls)));
        
        NSLog(@"==========================================================");
        
        
        
        // 是否是元类
        
        NSLog(@"MyClass is %@ a meta-class", (class_isMetaClass(cls) ? @"" : @"not"));
        
        NSLog(@"==========================================================");
        
        
        
        Class meta_class = objc_getMetaClass(class_getName(cls));
//        Class meta_class = objc_getMetaClass((__bridge void *)cls);
        
        NSLog(@"%s's meta-class is %s", class_getName(cls), class_getName(meta_class));
        
        NSLog(@"==========================================================");
        
        
        
        // 变量实例大小
        
        NSLog(@"instance size: %zu", class_getInstanceSize(cls));
        
        NSLog(@"==========================================================");
        
        
        
        // 成员变量
        
        Ivar *ivars = class_copyIvarList(cls, &outCount);
        
        for (int i = 0; i < outCount; i++) {
            
            Ivar ivar = ivars[i];
            
            NSLog(@"instance variable's name: %s at index: %d", ivar_getName(ivar), i);
            
        }
        
        
        
        free(ivars);
        
        
        
        Ivar string = class_getInstanceVariable(cls, "_string");
        
        if (string != NULL) {
            
            NSLog(@"instace variable %s", ivar_getName(string));
            
        }
        
        
        
        NSLog(@"==========================================================");
        
        
        
        // 属性操作
        
        objc_property_t * properties = class_copyPropertyList(cls, &outCount);
        
        for (int i = 0; i < outCount; i++) {
            
            objc_property_t property = properties[i];
            
            NSLog(@"property's name: %s", property_getName(property));
            
        }
        
        
        
        free(properties);
        
        
        
        objc_property_t array = class_getProperty(cls, "string");
        
        if (array != NULL) {
            
            NSLog(@"property %s", property_getName(array));
            
        }
        
        
        
        NSLog(@"==========================================================");
        
        
        
        // 方法操作
        
        Method *methods = class_copyMethodList(cls, &outCount);
        
        for (int i = 0; i < outCount; i++) {
            
            Method method = methods[i];
            
            NSLog(@"method's signature: %s", method_getName(method));
            
        }
        
        
        
        free(methods);
        
        
        
        Method method1 = class_getInstanceMethod(cls, @selector(method1));
        
        if (method1 != NULL) {
            
            NSLog(@"method %s", method_getName(method1));
            
        }
        
        
        
        Method classMethod = class_getClassMethod(cls, @selector(classMethod1));
        
        if (classMethod != NULL) {
            
            NSLog(@"class method : %s", method_getName(classMethod));
            
        }
        
        
        
        NSLog(@"MyClass is%@ responsd to selector: method3WithArg1:arg2:", class_respondsToSelector(cls, @selector(method3WithArg1:arg2:)) ? @"" : @" not");
        
        
        
        IMP imp = class_getMethodImplementation(cls, @selector(method1));
        
        imp();
        
        
        
        NSLog(@"==========================================================");
        
        
        
        // 协议
        
        Protocol * __unsafe_unretained * protocols = class_copyProtocolList(cls, &outCount);
        
        Protocol * protocol;
        
        for (int i = 0; i < outCount; i++) {
            
            protocol = protocols[i];
            
            NSLog(@"protocol name: %s", protocol_getName(protocol));
            
        }
        
        
        
        NSLog(@"MyClass is%@ responsed to protocol %s", class_conformsToProtocol(cls, protocol) ? @"" : @" not", protocol_getName(protocol));
        
        
        
        NSLog(@"==========================================================");
        
        
        
        Class clls = objc_allocateClassPair(myClass.class, "NewClass", 0);
        
        class_addMethod(clls, @selector(submethod1),(IMP)imp_submethod1, "v@:");
        
        class_addMethod(clls, @selector(method1), (IMP)imp_submethod1, "v@:");
        
        class_addIvar(clls, "_ivar1", sizeof(NSString*), log(sizeof(NSString*)), "i");
        
        objc_property_attribute_t type = {"T", "@\"NSString\""};
        objc_property_attribute_t ownership = { "C", "" };
        objc_property_attribute_t backingivar = { "V", "_ivar1"};
        objc_property_attribute_t attrs[] = {type, ownership, backingivar};
        
        class_addProperty(clls, "property2", attrs, 3);
        objc_registerClassPair(clls);
        
        id instance = [[clls alloc] init];
        [instance performSelector:@selector(method2)];
        [instance performSelector:@selector(method1)];
        
        
        NSLog(@"==========================================================");
        
        
//        NSArray *arr = @[@1,@2,@1,@5];
        
        int arr[] = {12.0,54.0,88.0,55555};
        
        NSLog(@"encod:%s",@encode(typeof(arr)));
        
        
    }
    
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
